package kbpost

import (
	"context"
	"fmt"
	"strconv"
	"strings"
	"time"

	"mall/common/globalkey"
	"mall/common/modelx"
	"mall/service/backend/common/errorx"
	"mall/service/backend/common/i18n"
	"mall/service/blog/model"
	"mall/service/blog/rpc/internal/svc"
	"mall/service/blog/rpc/internal/utils/errorhandler"
	"mall/service/blog/rpc/types/blog"

	"github.com/gosimple/slug"
	"github.com/sirupsen/logrus"
	"github.com/volatiletech/null/v8"
	"github.com/zeromicro/go-zero/core/logx"
)

type CreateKBPostLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewCreateKBPostLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateKBPostLogic {
	return &CreateKBPostLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *CreateKBPostLogic) CreateKBPost(in *blog.KBPostInfo) (*blog.BaseIDResp, error) {
	// logx.Infof("BackendCreatePost : %+v ", in)

	if in.Title == nil || len(strings.TrimSpace(*in.Title)) == 0 {
		return nil, errorx.NewInvalidArgumentError("cms.entryTitleRequired")
	}

	if in.SectionId == nil || *in.SectionId == 0 {
		return nil, errorx.NewInvalidArgumentError("cms.entrySectionRequired")
	}

	if in.Content == nil {
		return nil, errorx.NewInvalidArgumentError("cms.entryContentRequired")
	}

	title := strings.TrimSpace(*in.Title)
	entrySectionId := *in.SectionId
	var parentId uint64
	if in.ParentId == nil || *in.ParentId == 0 { // 是基础词条
		filterMap := make(map[string]map[string][]any)
		filterMap[model.BlogKnowledgeBasisColumns.SectionID] = map[string][]any{
			"equalTo": {entrySectionId},
		}
		filterMap[model.BlogKnowledgeBasisColumns.PostParentID] = map[string][]any{
			"equalTo": {0},
		}
		filterMap[model.BlogKnowledgeBasisColumns.PostTitle] = map[string][]any{
			"equalTo": {title},
		}
		if in.Slug != nil && len(strings.TrimSpace(*in.Slug)) > 0 {
			filterMap[model.BlogKnowledgeBasisColumns.PostName] = map[string][]any{
				"equalTo": {strings.TrimSpace(*in.Slug)},
			}
		}
		list, _, err := l.svcCtx.KBEntry.GetList(l.ctx, model.M{
			"pageSize": uint64(10),
			"select":   ",",
		}, -1, filterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if len(list) > 0 {
			return nil, errorx.NewInvalidArgumentError("cms.entryAlreadyExists")
		}

		// if len(list) > 0 { // 继续判断词条类型
		// 	var eids []any
		// 	for _, v := range list {
		// 		eids = append(eids, v.ID)
		// 	}

		// 	termFilterMap := make(map[string]map[string][]any)
		// 	termFilterMap[model.BlogTermRelationshipColumns.ObjectID] = map[string][]any{
		// 		"in": eids,
		// 	}
		// 	termFilterMap[model.BlogTermRelationshipColumns.ObjectType] = map[string][]any{
		// 		"equalTo": {globalkey.PostTypeKnowledgeBase},
		// 	}
		// 	termFilterMap[model.BlogTermRelationshipColumns.TermID] = map[string][]any{
		// 		"equalTo": {entrySectionId},
		// 	}
		// 	relationshipList, _, err := l.svcCtx.Term.GetRelationshipList(l.ctx, model.M{
		// 		"pageSize": uint64(10),
		// 		"select":   ",",
		// 	}, -1, termFilterMap)
		// 	if err != nil {
		// 		return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		// 	}

		// 	if len(relationshipList) > 0 {
		// 		return nil, errorx.NewInvalidArgumentError("cms.entryAlreadyExists")
		// 	}
		// }
	} else {
		parentId = *in.ParentId
	}

	now := time.Now()
	entry := &model.BlogKnowledgeBasis{
		SectionID:        entrySectionId,
		PostParentID:     parentId,
		PostTitle:        title,
		PostDate:         now,
		PostModifiedDate: now,
	}

	if in.Slug != nil && len(strings.TrimSpace(*in.Slug)) > 0 {
		entry.PostName = strings.TrimSpace(*in.Slug)
	}
	if in.Excerpt != nil && len(strings.TrimSpace(*in.Excerpt)) > 0 {
		entry.PostExcerpt = strings.TrimSpace(*in.Excerpt)
	}

	var visibility uint32
	if in.Visibility != nil && *in.Visibility > 0 {
		visibility = *in.Visibility
	}

	var publicDate time.Time
	var isFuturePublicDate bool
	if in.PublicDate != nil && len(*in.PublicDate) > 0 {
		if localTime, err := modelx.ParseLocalTime(*in.PublicDate); err == nil {
			publicDate = localTime
			isFuturePublicDate = true
		}
	}

	var status uint16
	var futureStatus int32  // 未来发布后的状态
	var pendingStatus int32 // 审核后的状态
	if in.Status != nil {
		if *in.Status == uint32(globalkey.PostStatusPublish) { // 发布
			if isFuturePublicDate { // 未来发布
				status = uint16(globalkey.PostStatusFuture)        // 暂为future状态
				if visibility == globalkey.PostVisibilityPrivate { // 未来发布后为private，否则为public
					futureStatus = globalkey.PostStatusPrivate
				} else {
					futureStatus = globalkey.PostStatusPublish
				}
			} else { // 立即发布
				if visibility == globalkey.PostVisibilityPrivate {
					status = uint16(globalkey.PostStatusPrivate)
				} else {
					status = uint16(globalkey.PostStatusPublish)
				}
			}
		} else { // 其他状态
			status = uint16(*in.Status)
			if isFuturePublicDate { // 未来发布
				pendingStatus = globalkey.PostStatusFuture         // 审核后为future状态
				if visibility == globalkey.PostVisibilityPrivate { // 审核且未来发布后为private，否则为public
					futureStatus = globalkey.PostStatusPrivate
				} else {
					futureStatus = globalkey.PostStatusPublish
				}
			} else { // 立即发布
				if visibility == globalkey.PostVisibilityPrivate {
					pendingStatus = globalkey.PostStatusPrivate
				} else {
					pendingStatus = globalkey.PostStatusPublish
				}
			}
		}
		entry.PostStatus = status
	} else {
		entry.PostStatus = uint16(globalkey.PostStatusAutoDraft)
	}

	if in.CommentStatus != nil && *in.CommentStatus > 0 {
		entry.CommentStatus = 1
	}
	if in.Sort != nil {
		entry.MenuOrder = int(*in.Sort)
	} else {
		entry.MenuOrder = int(9999)
	}
	if in.CreatedBy != nil {
		entry.PostAuthorID = *in.CreatedBy
	}

	if visibility == globalkey.PostVisibilityPasswordProtected && in.Password != nil {
		entry.PostPassword = strings.TrimSpace(*in.Password)
	}
	if isFuturePublicDate {
		entry.PostDate = publicDate
	}
	// var sticky string
	if in.Sticky != nil && *in.Sticky > 0 {
		entry.StickyType = uint8(*in.Sticky)
		// switch int32(*in.Sticky) {
		// case globalkey.BlogStickyTypeCategory:
		// 	sticky = "category"
		// case globalkey.BlogStickyTypeTag:
		// 	sticky = "tag"
		// default:
		// 	sticky = "frontpage"
		// }
	}

	rel := &model.KBEntryRel{
		Detail: &model.BlogKnowledgeBaseDetail{
			PostContent: *in.Content,
		},
		CategoryIds: in.CategoryIds,
		TagIds:      in.TagIds,
	}
	if in.ContentFiltered != nil {
		rel.Detail.PostContentFiltered = *in.ContentFiltered
	}

	var labelsIds []any
	relationEntityName := model.RpcEntityNames.BlogBookRelation
	if settingMap, ok := model.RpcEntityPreloadMap[relationEntityName]; ok {
		var uriTemplate string                // 当前词条 uri 模板
		var parentSectionId uint64            // 当前父级词条类型Section ID（当前为香水词条则为品牌词条类型ID）
		sectionMap := make(map[string]uint64) // 词条类型map 'Slug' => 'Id'
		groupMap := make(map[string]uint)     // 词条类型map 'Slug' => 'Group'
		var perfumeSectionId uint64           // 香水词条类型Section ID
		var parentEntryId uint64              // 当前香水词条 perfumes 的 parentId 为 brands 的 Id
		var parentEntrySlug string
		for _, v := range settingMap {
			if v.Id > 0 {
				if v.Id == entrySectionId {
					uriTemplate = v.UriTemplate
					if v.ParentId > 0 {
						parentSectionId = v.ParentId
					}
				}
				sectionMap[v.Slug] = v.Id
				if v.BothWay {
					perfumeSectionId = v.Id
				}
			}
			if v.Group > 0 {
				groupMap[v.Slug] = v.Group
			}
		}

		if in.RelationIds != nil && len(*in.RelationIds) > 0 {
			pairs := strings.Split(*in.RelationIds, ";")
			if len(pairs) > 0 {
				for _, pair := range pairs {
					parts := strings.Split(pair, ":")
					if len(parts) == 2 && len(parts[0]) > 0 && len(parts[1]) > 0 {
						section := parts[0]
						values := strings.Split(parts[1], ",")
						if len(values) > 0 {
							withLabels := false
							var sectionId uint64
							var groupId uint
							if setting, ok := settingMap[section]; ok { // 按slug简写查找
								sectionId = setting.Id
								groupId = setting.Group
							} else { // 前调、中调、后调、版本
								if settingId, ok := sectionMap[section]; ok { // 按slug查找
									if section == "brands" ||
										section == "fragrance families" ||
										section == "notes" {
										withLabels = true
									}
									sectionId = settingId
								}
								if gid, ok := groupMap[section]; ok {
									groupId = gid
								}
							}
							if sectionId > 0 {
								if withLabels {
									labelsIds = append(labelsIds, sectionId)
								}
								for idx, value := range values {
									if i, err := strconv.ParseInt(value, 10, 64); err == nil {
										rel.Relations = append(rel.Relations, &model.BlogKnowledgeBaseRelationship{
											FromSectionID: entrySectionId,
											ToEntryID:     uint64(i),
											ToSectionID:   sectionId,
											ToEntryGroup:  groupId,
											ToEntryOrder:  uint(idx),
											ToEntryMeta:   section,
										})
										if parentSectionId == 0 || parentEntryId > 0 { // 不是香水词条或者已找到品牌词条id
											continue
										}

										if sectionId == parentSectionId {
											parentEntryId = uint64(i)
										}
									}
								}
							}
						}
					}
				}
			}
		}

		if parentEntryId > 0 {
			parent, err := l.svcCtx.KBEntry.FindOneNoCache(l.ctx, nil, parentEntryId)
			if err != nil {
				return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
			}

			if len(parent.PostName) > 0 {
				parentEntrySlug = fmt.Sprintf("%s/", slug.Make(parent.PostName))
			}
		}

		if entry.PostParentID > 0 {
			rel.Versions = append(rel.Versions, &model.BlogKnowledgeBaseRelationship{
				FromEntryID:   entry.PostParentID,
				FromSectionID: perfumeSectionId,
				ToSectionID:   entrySectionId,
				ToEntryMeta:   "perfume-versions",
			})
		}

		if len(uriTemplate) > 0 {
			slug.Lowercase = false

			entry.GUID = fmt.Sprintf("%s%s%s/", uriTemplate, parentEntrySlug, slug.Make(entry.PostName))
		}
	}

	if len(in.Meta) > 0 {
		for _, v := range in.Meta {
			if v.Key == nil || len(strings.TrimSpace(*v.Key)) == 0 {
				continue
			}

			if v.Value == nil || len(strings.TrimSpace(*v.Value)) == 0 {
				continue
			}

			rel.Meta = append(rel.Meta, &model.BlogKnowledgeBaseMetum{
				MetaKey:   strings.TrimSpace(*v.Key),
				MetaValue: null.StringFrom(strings.TrimSpace(*v.Value)),
			})
		}
	}
	// if len(sticky) > 0 {
	// 	rel.Meta = append(rel.Meta, &model.BlogKnowledgeBaseMetum{
	// 		MetaKey:   "_sticky",
	// 		MetaValue: null.StringFrom(sticky),
	// 	})
	// }
	if futureStatus > 0 {
		rel.Meta = append(rel.Meta, &model.BlogKnowledgeBaseMetum{
			MetaKey:   "_future_status",
			MetaValue: null.StringFrom(strconv.FormatInt(int64(futureStatus), 10)),
		})
	}
	if pendingStatus > 0 {
		rel.Meta = append(rel.Meta, &model.BlogKnowledgeBaseMetum{
			MetaKey:   "_pending_status",
			MetaValue: null.StringFrom(strconv.FormatInt(int64(pendingStatus), 10)),
		})
	}

	allMediaMap := make(map[string]string)
	if len(in.AllMedia) > 0 {
		for _, v := range in.AllMedia {
			if v.Id != nil && v.Url != nil && len(*v.Id) > 0 && len(*v.Url) > 0 {
				allMediaMap[*v.Id] = *v.Url
			}
		}
	}

	if len(in.NewMedia) > 0 {
		var thumbnailOrder uint
		var thumbnailId uint64
		var thumbnailUrl string
		for idx, v := range in.NewMedia {
			var url string
			if v.Url != nil && len(*v.Url) > 0 {
				url = *v.Url
			}
			var uri string
			if v.Uri != nil && len(*v.Uri) > 0 {
				uri = *v.Uri
				if len(url) == 0 {
					url = uri
				}
			}
			if len(url) == 0 {
				continue
			}

			var thumbnail uint8
			if v.Thumbnail != nil && *v.Thumbnail > 0 {
				thumbnail = uint8(*v.Thumbnail)
			}
			var order uint
			if v.Order != nil {
				order = uint(*v.Order)
			} else {
				order = uint(idx) + globalkey.AttachmentOrderOffset
			}
			var altText string
			if v.AltText != nil && len(*v.AltText) > 0 {
				altText = *v.AltText
			}

			var meta []string
			if v.Name != nil && len(*v.Name) > 0 {
				meta = append(meta, "filename:"+*v.Name)
				if len(altText) == 0 {
					altText = *v.Name
				}
			}
			if v.MetaData != nil && len(*v.MetaData) > 0 {
				meta = append(meta, *v.MetaData)
			}
			if v.MimeType != nil && len(*v.MimeType) > 0 {
				meta = append(meta, "mimeType:"+*v.MimeType)
			}
			metaData := strings.Join(meta, ";")

			var mediaId uint64
			if v.Id != nil && len(*v.Id) > 0 {
				if i, err := strconv.ParseInt(*v.Id, 10, 64); err == nil {
					mediaId = uint64(i)
				}
			}

			media := &model.BlogAttachmentRelationship{
				AttachmentID:        mediaId,
				AttachmentThumbnail: thumbnail,
				AttachmentOrder:     order,
				AttachmentImageURL:  url,
				AttachmentImageAlt:  altText,
				AttachmentImageMeta: metaData,
			}

			if thumbnail == 0 && mediaId > 0 {
				if uri, ok := allMediaMap[*v.Id]; ok {
					media.AttachmentSource = uri
				}
			}

			rel.Media = append(rel.Media, media)

			if thumbnail > 0 && (len(thumbnailUrl) == 0 || thumbnailOrder > order) { // thumbnailOrder尚未赋值，或当前值更小
				thumbnailOrder = order
				thumbnailId = mediaId
				thumbnailUrl = url
			}
		}

		if len(thumbnailUrl) > 0 {
			rel.Meta = append(rel.Meta, &model.BlogKnowledgeBaseMetum{
				MetaKey:   "_thumbnail_id",
				MetaValue: null.StringFrom(strconv.FormatInt(int64(thumbnailId), 10)),
			})
			rel.Meta = append(rel.Meta, &model.BlogKnowledgeBaseMetum{
				MetaKey:   "_thumbnail_url",
				MetaValue: null.StringFrom(thumbnailUrl),
			})
		}
		rel.Meta = append(rel.Meta, &model.BlogKnowledgeBaseMetum{
			MetaKey:   "_photo_count",
			MetaValue: null.StringFrom(strconv.FormatInt(int64(len(rel.Media)), 10)),
		})
	}

	tx, err := l.svcCtx.DB.BeginTx(l.ctx, nil)
	if err != nil {
		return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
	}

	err = l.svcCtx.KBEntry.Insert(l.ctx, tx, entry, rel)
	if err != nil {
		tx.Rollback()
		return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
	}

	tx.Commit()

	if entry.PostParentID > 0 {
		_, err = l.svcCtx.KBEntry.UpdateMeta(l.ctx, nil, &model.BlogKnowledgeBaseMetum{
			KnowledgeBaseID: entry.PostParentID,
			MetaKey:         "_version_count",
			MetaValue:       null.StringFrom("1"),
		}, 1)
		if err != nil {
			logrus.Info(fmt.Sprintf("CreateKBPost VersionCount error, err: %+v", err))
		}
	}

	var labels []string
	if len(labelsIds) > 0 {
		labelsFilterMap := make(map[string]map[string][]any)
		labelsFilterMap[model.BlogKnowledgeBasisColumns.ID] = map[string][]any{
			"in": labelsIds,
		}
		list, _, err := l.svcCtx.KBEntry.GetList(l.ctx, model.M{
			"select": model.BlogKnowledgeBasisColumns.PostTitle,
		}, -1, labelsFilterMap)
		if err != nil {
			logx.Errorf("CreateKBPost GetList Error: %+v", err)
		}
		if len(list) > 0 {
			for _, v := range list {
				if len(v.PostTitle) > 0 {
					labels = append(labels, v.PostTitle)
				}
			}
		}
	}

	if len(labels) > 0 {
		err = l.createItem("entry:"+strconv.FormatUint(*in.Id, 10), labels)
		if err != nil {
			logx.Errorf("AddEntryFavorite createFeedBack Error: %v", err)
		}
	}

	return &blog.BaseIDResp{
		Id:  entry.ID,
		Msg: i18n.CreateSuccess,
	}, nil
}

func (l *CreateKBPostLogic) createItem(pid string, labels []string) error {
	return l.svcCtx.GorseClient.CreateItem(
		l.svcCtx.Config.Query.GorseUrl,
		pid, "", "1",
		labels, strings.Split(strconv.FormatInt(int64(globalkey.AttachmentLogKbEntry), 10), ","),
	)
}
